home *** CD-ROM | disk | FTP | other *** search
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Runtime.Remoting.Contexts;
- using System.Text.RegularExpressions;
- using System.Threading;
- using System.Web;
- using System.Web.SessionState;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Web.UI.HtmlControls;
- using System.Xml;
- using GBPVRSchedule;
- using Microsoft.Win32;
- using System.Drawing;
-
- using Microsoft.Win32;
-
- using GBPVR.Public;
-
- using ICSharpCode.SharpZipLib.Zip;
-
- namespace gbweb
- {
- /// <summary>
- /// Summary description for Download.
- /// </summary>
- public class Download : IRequiresSessionState, IHttpHandler
- {
- private const int buffersize = 500000; // bytes (this is size of packet)
- private const int bufferdelay = 100; // milliSeconds (this is time between end of packet n, and start of packet n + 1)
- // Where Bps = bytes/sec:
- // buffersize * bufferdelay gives us our max download rate of 5MBps.
- // (very roughly because we delay between packets (start2-end1), and don't count time between the start of packets (start2-start1)
- // Moonlight encoder default is VBR with an average of 0.4MBps, and max of 0.9MBps.
- // The maximum rate possible that Moonlight supports is 1.5MBps.
-
- public enum InternalFiles
- {
- Log = -1,
- LibraryFile = -2,
- LiveTV = -3,
- LibraryFolder = -4,
- ChannelIcon = -5,
- Photo = -6,
- ModifiedPhoto = -7
- }
-
- #region IHttpHandler Members
-
- public void ProcessRequest(HttpContext context)
- {
- string path = context.Request.PathInfo.TrimStart('/');
- string[] ridInfo = path.Split(',');
-
- int rid = Convert.ToInt32(ridInfo[0]);
- bool direct = ridInfo[1] == "1";
- path = HttpUtility.UrlDecode(context.Request.Url.Query.TrimStart('?'));
-
- ProcessDownload(context.Request, context.Response, direct, rid, path);
- }
-
- public bool IsReusable
- {
- get
- {
- return true;
- }
- }
-
- #endregion
-
- #region GetDownloadUrl
-
- public static string GetDownloadUrl(bool anon, bool direct, InternalFiles internalType)
- {
- return GetDownloadUrl(anon, direct, (int)internalType);
- }
-
- public static string GetDownloadUrl(bool anon, bool direct, InternalFiles internalType, string path)
- {
- return GetDownloadUrl(anon, direct, (int)internalType, path);
- }
-
- public static string GetDownloadUrl(bool anon, bool direct, int rid)
- {
- return GetDownloadUrl(anon, direct, rid, null);
- }
-
- public static string GetDownloadUrl(bool anon, bool direct, int rid, string path)
- {
- string url;
- if (anon)
- {
- url = "public/download.aspx?rid=" + PublicDownload.Serialize(rid);
- if (path != null) url += "&path=" + PublicDownload.Serialize(path);
- if (direct) url += "&mode=1";
- }
- else
- {
- url = "public/download.ashx/" + rid.ToString() + (direct ? ",1" : ",0");
- if (path != null) url += "?" + path;
- }
- return url;
- }
-
- #endregion
- #region ProcessDownload
-
- public static void ProcessDownload(HttpRequest Request, HttpResponse Response, bool direct, int rid, string path)
- {
- Schedule scheduleHelper = Global.Schedule;
-
- string fileName = null;
- string contentType = null;
- bool attachment = true;
- bool seekable = true;
-
- ScheduledRecording recording = null;
-
- switch (rid)
- {
- case (int)InternalFiles.Log:
- string logfolder = typeof(GBPVR.Public.ScheduledRecording).Assembly.GetModules()[0].FullyQualifiedName;
- logfolder = logfolder.Substring(0, logfolder.LastIndexOf(@"\")) + "\\logs";
- string logname = AppDomain.CurrentDomain.FriendlyName + ".log";
- fileName = Path.Combine(logfolder, logname);
- contentType = "text/plain";
- seekable = false;
- attachment = false;
- break;
- case (int)InternalFiles.LibraryFile:
- try
- {
- fileName = Library.GetRealPath(path);
- }
- catch
- {
- return;
- }
- break;
- case (int)InternalFiles.LibraryFolder:
- handleLibraryFolder(Request, Response, direct, path);
- break;
- case (int)InternalFiles.LiveTV:
- string[] tuners = Info.GetRecordingService().getTunerStatus();
- string currentStatus = tuners[Convert.ToInt32(path)];
- Match match = Info.liveTVRegex.Match(currentStatus);
- XmlNode node = Global.Config.SelectSingleNode("/settings/LiveTVDirectory");
- if ((node != null) && (match.Captures.Count == 1))
- {
- fileName = Path.Combine(node.InnerText, match.Groups[1].ToString());
- }
- seekable = false;
- break;
- case (int)InternalFiles.ChannelIcon:
- fileName = Path.Combine(Path.Combine(Global.Settings.GetInstallDir(), @"media\ChannelLogos\"), path);
- break;
- case (int)InternalFiles.Photo:
- //This means we want to stream a photo that does not need to be rotated
- //Deserialize the passed path
- fileName = (string) PublicDownload.Deseralize(path);
- break;
- case (int)InternalFiles.ModifiedPhoto:
- //This means we want to stream a photo that someone has requested to rotate.
- //Deserialize the passed path
- fileName = (string)PublicDownload.Deseralize(path);
- //The path contains all the parms needed to find, size and rotate the image so each gets split out into
- //an array for easy access
- //0 = filename, 1 = desired heigth, 2 = desired width, 3 = rotation option
- string[] parm = fileName.Split('~');
- ModifyPhoto(Response, parm[0], Convert.ToInt32(parm[1]), Convert.ToInt32(parm[2]), Convert.ToInt32(parm[3]));
- //Since the above already streamed the image then we are done here
- return;
- break;
- default:
- ScheduledRecording scheduledRecording = scheduleHelper.GetScheduledRecordingByOID(rid);
- if (scheduledRecording != null)
- {
- recording = scheduledRecording;
- fileName = recording.getFileName();
- }
- break;
- }
-
- if (fileName == null) return;
-
- Response.Clear();
-
- if ((!direct) && (attachment))
- {
- int seconds = -1;
- if (recording != null) seconds = (int)((TimeSpan)(recording.getEndTime() - recording.getStartTime())).TotalSeconds;
-
- Response.AppendHeader("Content-Type", "audio/mpegurl");
- Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileNameWithoutExtension(fileName) + "." + Global.Settings.playlistExtension + "\"");
- Response.Write("#EXTM3U\r\n");
- Response.Write("#EXTINF:" + seconds + "," + Path.GetFileNameWithoutExtension(fileName) + "\r\n");
- string url = Request.Url.ToString().Replace(
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Url.Authority,
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Headers["Host"]);
- url = url.Substring(0, url.IndexOf("public/download.ashx"));
- url += GetDownloadUrl(true, true, rid, path);
- Response.Write(url + "\r\n");
- Response.End();
- return;
- }
-
- try
- {
- RegistryKey fileTypeKey = Registry.ClassesRoot.OpenSubKey(Path.GetExtension(fileName));
- string autocontentType = (string)fileTypeKey.GetValue("Content Type");
- fileTypeKey.Close();
- if (autocontentType != null) contentType = autocontentType;
- }
- catch
- {
- }
-
- if (contentType != null)
- {
- Response.AppendHeader("Content-Type", contentType);
- }
-
- Response.Buffer = false;
-
- Stream infile = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
- long startbyte = 0;
- long stopbyte = infile.Length - 1;
-
- string range = Request.Headers["Range"];
- if (range != null)
- {
- Response.StatusCode = 206;
- string[] info = range.Split('=', '-');
- if ((info.Length > 1) && (info[1].Length > 0))
- startbyte = Convert.ToInt64(info[1]);
- if ((info.Length > 2) && (info[2].Length > 0))
- stopbyte = Convert.ToInt64(info[2]);
- Response.AppendHeader("Content-Range", "bytes " + startbyte.ToString() + "-" + stopbyte.ToString() + "/" + infile.Length.ToString());
- }
-
- long length = stopbyte - startbyte + 1;
- if (attachment)
- Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(fileName) + "\"");
- else
- Response.AppendHeader("Content-Disposition", "inline; filename=\"" + Path.GetFileName(fileName) + "\"");
- if (seekable)
- {
- Response.AppendHeader("Accept-Ranges", "bytes");
- try
- {
- Response.AppendHeader("Content-Length", length.ToString());
- }
- catch (OverflowException)
- {
- // ugh, .Net v1.1 defined the Content-Length as an Int32.
- Response.AppendHeader("Content-Length", Int32.MaxValue.ToString());
- }
- }
- Response.AppendHeader("icy-name", Path.GetFileName(fileName));
- Response.Cache.SetLastModified(File.GetLastWriteTime(fileName));
- Response.Cache.SetExpires(DateTime.Now.AddDays(1));
-
- infile.Position = startbyte;
-
- WriteLargeFileSlowly(Response, infile, Response.OutputStream, rid.ToString());
-
- Response.End();
- }
-
- private static void WriteLargeFileSlowly(HttpResponse Response, Stream infile, Stream outfile, string logID)
- {
- // Response.WriteFile(fileName, startbyte, length);
- // WriteFile doesn't allow us to control the max download speed.
- // Also in .Net v1.1 / Cassini it doesn't allow > 2GB files to be downloaded.
-
- byte[] buffer = new byte[buffersize];
-
- int readcount = infile.Read(buffer, 0, buffersize);
-
- while (readcount > 0)
- {
- try
- {
- outfile.Write(buffer, 0, readcount);
- }
- catch (Exception ex)
- {
- Logger.Error("[" + logID + "]: outfile.Write Exception: " + ex.ToString());
- break;
- }
- Thread.Sleep(bufferdelay);
- readcount = infile.Read(buffer, 0, buffersize);
- if (!Response.IsClientConnected)
- {
- Logger.Error("[" + logID + "]: Client Not Connected");
- break;
- }
- }
- if (readcount != 0) Logger.Error("[" + logID + "]: Read Count Non-Zero");
- infile.Close();
- }
-
- public static string streamLibraryFolder(HttpRequest Request, string vpath)
- {
- string[] pathparts = vpath.Split(new char[] { '/' }, 3);
- Regex fileFilter = Library.GetRegex(pathparts[0]);
-
- string path = Library.GetRealPath(vpath);
-
- string[] filenames = Directory.GetFiles(path);
- Array.Sort(filenames);
-
- string tmpDir = Environment.GetEnvironmentVariable("ALLUSERSPROFILE");
- FileInfo playlist = new FileInfo(tmpDir + "\\playlist.m3u");
- StreamWriter sw = playlist.CreateText();
-
- //sw.WriteLine("Content-Type", "audio/mpegurl");
- //sw.WriteLine("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(Path.GetDirectoryName(path)) + "." + Global.Settings.playlistExtension + "\"");
- sw.Write("#EXTM3U\r\n");
-
- string urlroot = Request.Url.ToString().Replace(
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Url.Authority,
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Headers["Host"]);
- if (urlroot.Contains("Player.aspx"))
- {
- urlroot = urlroot.Substring(0, urlroot.IndexOf("Player.aspx"));
- }
-
- foreach (string filename in filenames)
- {
- if ((filename == Path.GetFullPath(filename)) && (fileFilter.IsMatch(filename)))
- {
- sw.Write("#EXTINF:0," + Path.GetFileNameWithoutExtension(filename) + "\r\n");
- //string url =
- // urlroot + GetDownloadUrl(true, true, Download.InternalFiles.LibraryFile, vpath + Path.GetFileName(filename));
- sw.Write(filename + "\r\n");
- }
- }
- sw.Close();
- return(playlist.Name);
- }
-
- private static void handleLibraryFolder(HttpRequest Request, HttpResponse Response, bool direct, string vpath)
- {
- string[] pathparts = vpath.Split(new char[] {'/'}, 3);
- Regex fileFilter = Library.GetRegex(pathparts[0]);
-
- string path = Library.GetRealPath(vpath);
-
- string[] filenames = Directory.GetFiles(path);
- Array.Sort(filenames);
-
- if (!direct)
- {
- Response.AppendHeader("Content-Type", "audio/mpegurl");
- Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(Path.GetDirectoryName(path)) + "." + Global.Settings.playlistExtension + "\"");
- Response.Write("#EXTM3U\r\n");
-
- string urlroot = Request.Url.ToString().Replace(
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Url.Authority,
- Request.Url.Scheme + Uri.SchemeDelimiter + Request.Headers["Host"]);
- urlroot = urlroot.Substring(0, urlroot.IndexOf("public/download.ashx"));
- foreach (string filename in filenames)
- {
- if ((filename == Path.GetFullPath(filename)) && (fileFilter.IsMatch(filename)))
- {
- Response.Write("#EXTINF:0," + Path.GetFileNameWithoutExtension(filename) + "\r\n");
- string url =
- urlroot + GetDownloadUrl(true, true, Download.InternalFiles.LibraryFile, vpath + Path.GetFileName(filename));
- Response.Write(url + "\r\n");
- }
- }
- }
- else
- {
- Response.AppendHeader("Content-Type", "application/zip");
- Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + Path.GetFileName(Path.GetDirectoryName(path)) + ".zip\"");
-
- ZipOutputStream s = new ZipOutputStream(Response.OutputStream);
- s.SetLevel(0);
-
- foreach (string filename in filenames)
- {
- if ((filename == Path.GetFullPath(filename)) && (fileFilter.IsMatch(filename)))
- {
- FileStream fs = File.OpenRead(filename);
-
- ZipEntry entry = new ZipEntry(Path.Combine(Path.GetFileName(Path.GetDirectoryName(filename)), Path.GetFileName(filename)));
- entry.Size = fs.Length;
- s.PutNextEntry(entry);
-
- WriteLargeFileSlowly(Response, fs, s, filename);
- fs.Close();
- }
- }
-
- s.Finish();
- s.Close();
-
- }
-
- Response.End();
- }
-
- private static void ModifyPhoto(HttpResponse Response, string filepath, int H, int W, int R)
- {
-
- //Create the image from the file location
- System.Drawing.Image image = System.Drawing.Image.FromFile(filepath);
-
- //Rotate the image based on what the user selected
- switch (R)
- {
- case 1:
- {
- image.RotateFlip(RotateFlipType.Rotate90FlipNone);
- break;
- }
- case 2:
- {
- image.RotateFlip(RotateFlipType.Rotate180FlipNone);
- break;
- }
- case 3:
- {
- image.RotateFlip(RotateFlipType.Rotate270FlipNone);
- break;
- }
- }
-
- // create a new image that matches the size that the user wants
- System.Drawing.Image thumbnailImage = image.GetThumbnailImage(W, H, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
-
- //Write (save) the new image back to the browser....in this case it is filling the image control
- thumbnailImage.Save(Response.OutputStream, ImageFormat.Jpeg);
- //Celanup
- image.Dispose();
- thumbnailImage.Dispose();
- Response.Flush();
-
- }
-
- public static bool ThumbnailCallback()
- {
- return true;
- }
-
- #endregion
-
- }
- }
-